package cn.gov.anhai.utils;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiFunction;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
public class CallUtils {
    public static String remoteCall(HttpUriRequest request) throws IOException {
        return remoteCall(request, CallUtils::commonErrorHandler);
    }
    public static <E extends Exception> String remoteCall(HttpUriRequest request,
                                                          BiFunction<CloseableHttpResponse, String, E> errorHandler) throws IOException, E {
        CloseableHttpResponse response = getClient().execute(request);
        try {
            HttpEntity responseEntity = response.getEntity();
            String ret = responseEntity != null ? EntityUtils.toString(responseEntity) : null;
            EntityUtils.consume(responseEntity);
            if (errorHandler != null) {
                E error = errorHandler.apply(response, ret);
                if (null != error) {
                    throw error;
                }
            }
            return ret;
        } finally {
            response.close();
        }
    }
    public static Map<String, Object> toJsonObject(String json) {
        return (JSONObject) JSON.parse(json);
    }
    public static IOException commonErrorHandler(CloseableHttpResponse response, String rawBody) {
        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode != 200) {
            return new IOException("call failed! status:" + statusCode + ", response data: " + rawBody);
        }
        Header nspStatus = response.getFirstHeader("NSP_STATUS");
        if (Objects.nonNull(nspStatus)) {
            return new IOException("call failed! nsp_status:" + nspStatus.getValue() + ", response data: " + rawBody);
        }
        return null;
    }
    private static CloseableHttpClient getClient() {
        PoolingHttpClientConnectionManager connectionManager = buildConnectionManager(
                new String[] {"TLSv1.2", "TLSv1.1"}, new String[] {
                        "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
                        "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"
                });
        connectionManager.setMaxTotal(400);
        connectionManager.setDefaultMaxPerRoute(400);
        RequestConfig config = RequestConfig.custom()
                .setConnectionRequestTimeout(100)
                .setRedirectsEnabled(false)
                .build();
        return HttpClients.custom()
                .useSystemProperties()
                .setConnectionManager(connectionManager)
                .setDefaultRequestConfig(config)
                .build();
    }
    private static PoolingHttpClientConnectionManager buildConnectionManager(String[] supportedProtocols,
                                                                             String[] supportedCipherSuites) {
        PoolingHttpClientConnectionManager connectionManager = null;
        try {
            SSLContext sc = SSLContext.getInstance("TLSv1.2");
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init((KeyStore) null);
            sc.init(null, tmf.getTrustManagers(), null);
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sc, supportedProtocols,
                    supportedCipherSuites, SSLConnectionSocketFactory.getDefaultHostnameVerifier());
            Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register("http", new PlainConnectionSocketFactory())
                    .register("https", sslsf)
                    .build();
            connectionManager = new PoolingHttpClientConnectionManager(registry);
        } catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) {
            e.printStackTrace();
        }
        return connectionManager;
    }
}